package edu.uwosh.cs342.group2.project4.database;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONObject;

import android.content.Context;
import android.os.AsyncTask;
import android.util.Pair;
import android.widget.Toast;

import edu.uwosh.cs342.group2.project4.storage.Category;
import edu.uwosh.cs342.group2.project4.storage.Coordinates;
import edu.uwosh.cs342.group2.project4.storage.Location;

/**
 * Calls database classes through a asynchronous task
 * @author Drew McCauley
 *
 */
public class ThreadedDbHelper {
	
	private Context context;
	
	/**
	 * Default constructor for the threaded Db helper
	 * @param context
	 */
	public ThreadedDbHelper(Context context) {
		this.context = context;
	}
	
	/**
	 * Adds a category to the database
	 * @param name name of the category
	 * @return
	 */
	public int AddCategory(String name) {
		AddCategoryTask task = new AddCategoryTask();
		int id = -1;
		task.execute(name);
		try {
			id = task.get();
		}
		catch (Exception e) {
			id = -1;
		}
		
		return id;
	}
	
	/**
	 * Gets the category by the unique ID
	 * @param id
	 * @return
	 */
	public Category GetCategory(int id) {
		GetCategoryTask task = new GetCategoryTask();
		Category category = null;
		task.execute(id);
		try {
			category = task.get();
		}
		catch(Exception e) {
			category = null;
		}
		
		return category;
	}
	
	/**
	 * Gets all of the categories
	 * @return
	 */
	public ArrayList<Category> GetAllCategories() {
		GetAllCategoriesTask task = new GetAllCategoriesTask();
		ArrayList<Category> categories = null;
		task.execute();
		try {
			categories = task.get();
		}
		catch (Exception e) {
			categories = null;
		}
		
		return categories;
	}
	
	/**
	 * Updates the category's information
	 * @param category
	 * @return
	 */
	public boolean UpdateCategory(Category category) {
		UpdateCategoryTask task = new UpdateCategoryTask();
		boolean success = false;
		task.execute(category);
		try {
			success = task.get();
		}
		catch (Exception e) {
			success = false;
		}
		
		return success;
	}
	
	/**
	 * Removes the category from the list
	 * @param id
	 * @return
	 */
	public boolean RemoveCategory(int id) {
		RemoveCategoryTask task = new RemoveCategoryTask();
		boolean success = false;
		task.execute(id);
		try {
			success = task.get();
		}
		catch (Exception e) {
			success = false;
		}
		
		return success;
	}
	
	/**
	 * Adds a location to the database
	 * @param location
	 * @return
	 */
	public int AddLocation(Location location) {
		AddLocationTask task = new AddLocationTask();
		int id = -1;
		task.execute(location);
		try {
			id = task.get();
		}
		catch (Exception e) {
			id = -1;
		}
		
		return id;
	}
	
	/**
	 * Gets the location by the unique ID
	 * @param id
	 * @return
	 */
	public Location GetLocation(int id) {
		GetLocationTask task = new GetLocationTask();
		Location location = null;
		task.execute(id);
		try {
			location = task.get();
		}
		catch (Exception e) {
			location = null;
		}
		
		return location;
	}
	
	/**
	 * Gets all of the location
	 * @return
	 */
	public ArrayList<Location> GetAllLocations() {
		GetAllLocationsTask task = new GetAllLocationsTask();
		ArrayList<Location> locations = null;
		task.execute();
		try {
			locations = task.get();
		}
		catch (Exception e) {
			locations = null;
		}
		
		return locations;
	}
	
	/**
	 * Updates the location's information
	 * @param location
	 * @return
	 */
	public boolean UpdateLocation(Location location) {
		UpdateLocationTask task = new UpdateLocationTask();
		boolean success = false;
		task.execute(location);
		try {
			success = task.get();
		}
		catch (Exception e) {
			success = false;
		}
		
		return success;
	}
	
	/**
	 * Removes the location from the list
	 * @param id
	 * @return
	 */
	public boolean RemoveLocation(int id) {
		RemoveLocationTask task = new RemoveLocationTask();
		boolean success = false;
		task.execute(id);
		try {
			success = task.get();
		}
		catch (Exception e) {
			success = false;
		}
		
		return success;
	}
	
	/**
	 * Searches google places API for nearby places
	 * @param coords
	 * @param radius
	 * @param sensor
	 * @param pairs
	 * @return
	 */
	public ArrayList<Location> SearchPlaces(Coordinates coords, float radius, boolean sensor, Pair<String, String>[] pairs) {
		SearchPlacesTask task = new SearchPlacesTask();
		String jsonString = null;
		task.execute(coords, radius, sensor, pairs);
		try {
			jsonString = task.get();
		}
		catch (Exception e) {
			jsonString = null;
		}
        
		//TODO: change return type to the list
		// Parse the JSON HERE!!!! HERE!!!! NO WHERE ELSE, HERE!!!!
		// Then return it as the list, or whatever your JSON parses to HERE!!!!!!!!!!!!!
		
		 ArrayList<Location> loc  = new ArrayList<Location>();
        try{
        	  JSONObject jsonObject = new JSONObject(jsonString);
              JSONArray results = jsonObject.getJSONArray("results");
            
              
              for(int i = 0; i < results.length(); i++){
            	 Location t = new Location();
           	 t.setName(results.getJSONObject(i).getString("name").toString());
           	 JSONArray type = results.getJSONObject(i).getJSONArray("types");
           	 t.setDescription(type.get(0).toString().replaceAll("_", " ") + " " + type.get(1).toString().replaceAll("_", " "));
           	 
           	 JSONObject o = results.getJSONObject(i).getJSONObject("geometry");
            JSONObject o1 = o.getJSONObject("location");
                  Double lat = o1.getDouble("lat");
               Double lng = o1.getDouble("lng");	 
            	 
            	 t.setCoordinates(new Coordinates(lat, lng));
           	 
           	 loc.add(t);
              }
        }catch(Exception e){
        	 
        }
        
   	   
        
		return loc; // <-- This return type
	}
	
	/**
	 * Adds a category to the database
	 * @author Drew McCauley
	 *
	 */
	private class AddCategoryTask extends AsyncTask<String, Void, Integer> {
		@Override
		protected Integer doInBackground(String... params) {
			return new CategoryDb(context).AddCategory(params[0]);
		}
	}
	
	/**
	 * Gets a category from the database
	 * @author Drew McCauley
	 *
	 */
	private class GetCategoryTask extends AsyncTask<Integer, Void, Category> {
		@Override
		protected Category doInBackground(Integer... params) {
			return new CategoryDb(context).GetCategory(params[0]);
		}
	}
	
	/**
	 * Gets all of the categories from the database
	 * @author Drew McCauley
	 *
	 */
	private class GetAllCategoriesTask extends AsyncTask<Void, Void, ArrayList<Category>> {
		@Override
		protected ArrayList<Category> doInBackground(Void... params) {
			return new CategoryDb(context).GetAllCategories();
		}
	}
	
	/**
	 * Updates the category to the database
	 * @author Drew McCauley
	 *
	 */
	private class UpdateCategoryTask extends AsyncTask<Category, Void, Boolean> {
		@Override
		protected Boolean doInBackground(Category... params) {
			return new CategoryDb(context).UpdateCategory(params[0]);
		}
	}
	
	/**
	 * Removes a category from the database
	 * @author Drew McCauley
	 *
	 */
	private class RemoveCategoryTask extends AsyncTask<Integer, Void, Boolean> {
		@Override
		protected Boolean doInBackground(Integer... params) {
			return new CategoryDb(context).RemoveCategory(params[0]);
		}
	}
	
	/**
	 * Adds a location to the database
	 * @author Drew McCauley
	 *
	 */
	private class AddLocationTask extends AsyncTask<Location, Void, Integer> { 
		@Override
		protected Integer doInBackground(Location... params) {
			return new LocationDb(context).AddLocation(params[0]);
		}
	}
	
	/**
	 * Gets a location from the database
	 * @author Drew McCauley
	 *
	 */
	private class GetLocationTask extends AsyncTask<Integer, Void, Location> {
		@Override
		protected Location doInBackground(Integer... params) {
			return new LocationDb(context).GetLocation(params[0]);
		}
	}
	
	/**
	 * Gets all of the location in the database
	 * @author Drew McCauley
	 *
	 */
	private class GetAllLocationsTask extends AsyncTask<Void, Void, ArrayList<Location>> {
		@Override
		protected ArrayList<Location> doInBackground(Void... params) {
			return new LocationDb(context).GetAllLocations();
		}
	}
	
	/**
	 * Updates the location in the database
	 * @author Drew McCauley
	 *
	 */
	private class UpdateLocationTask extends AsyncTask<Location, Void, Boolean> {
		@Override
		protected Boolean doInBackground(Location... params) {
			return new LocationDb(context).UpdateLocation(params[0]);
		}
	}
	
	/**
	 * Removes the location from the database
	 * @author Drew McCauley
	 *
	 */
	private class RemoveLocationTask extends AsyncTask<Integer, Void, Boolean> {
		@Override
		protected Boolean doInBackground(Integer... params) {
			return new LocationDb(context).RemoveLocation(params[0]);
		}
	}
	
	/**
	 * Searches places and returns a string to the user
	 * @author Drew McCauley
	 *
	 */
	private class SearchPlacesTask extends AsyncTask<Object, Void, String> {
		@SuppressWarnings("unchecked")
		@Override
		protected String doInBackground(Object... params) {
			Pair<String, String>[] param3 = null;
			try {
				param3 = (Pair<String, String>[])params[3];
			}
			catch (Exception e) {
				System.out.println("param3 wasn't pair<str, str>[] checked right");
			}
			return new PlacesDb().SearchPlaces((Coordinates)params[0], (Float)params[1], (Boolean)params[2], param3);
		}
	}
}
